﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.GData.Calendar;
using System.Diagnostics;
using SpeakupBackend.Classes;
using Google.GData.Extensions;
using Google.GData.Client;
using System.Net;
using SpeakupReminder = SpeakupBackend.Reminder;

namespace GoogleCalendar
{
    public class CalendarFacade
    {
        private readonly Uri OwnCalendarsUri = new Uri("https://www.google.com/calendar/feeds/default/owncalendars/full");
        private const string ApplicationName = "speakup-frontend-1";
        private const string SpeakupCalendarName = "SpeakupClasses";

        private string m_name;
        public string Name 
        {
            get
            {
                return m_name;
            }

            set
            {
                m_name = value;
                if(m_calendarService != null && m_password != null)
                {
                    m_calendarService.setUserCredentials(value, m_password);
                }
            }
        }

        private string m_password;
        public string Password 
        { 
            get
            {
                return m_password;
            }
            set
            {
                m_password = value;
                if(m_calendarService != null && m_name != null)
                {
                    m_calendarService.setUserCredentials(m_name, m_password);
                }
            }
        }

        private SpeakupReminder m_reminder;
        public SpeakupReminder Reminder
        {
            get
            {
                return m_reminder;
            }
            set
            {
                m_reminder = value;
            }
        }

        private CalendarService m_calendarService;
        private CalendarService CalendarService
        {
            get
            {
                if (m_calendarService == null)
                {
                    m_calendarService = new CalendarService(ApplicationName);

                    if(m_name != null && m_password != null)
                    {
                        m_calendarService.setUserCredentials(m_name, m_password);
                    }
                }

                return m_calendarService;
            }
        }

        private Uri m_calendarUri;
        private Uri CalendarUri
        {
            get
            {
                if (m_calendarUri == null)
                {
                    m_calendarUri = GetCalendarUri();
                }

                return m_calendarUri;
            }
        }

        public CalendarFacade(string name, string password)
        {
            Name = name;
            Password = password;
        }
        
        private Uri GetCalendarUri()
        {
            String uriTemplate = "https://www.google.com/calendar/feeds/{0}/private/full";

            CalendarQuery query = new CalendarQuery();
            query.Uri = OwnCalendarsUri;

            Uri absoluteUri = null;

            CalendarFeed resultFeed = (CalendarFeed)CalendarService.Query(query);
            foreach (CalendarEntry entry in resultFeed.Entries)
            {
                if (entry.Title.Text == SpeakupCalendarName)
                {
                    absoluteUri = new Uri(entry.Id.AbsoluteUri);
                    break;
                }
            }

            if (absoluteUri == null)
            {
                Trace.TraceInformation("Calendar \"{0}\" does not exist. Creating.", SpeakupCalendarName);

                CalendarEntry calendar = new CalendarEntry();
                calendar.Title.Text = SpeakupCalendarName;
                calendar.Summary.Text = "This calendar contains all reserved speakup classes.";
                calendar.Hidden = false;
                calendar.Color = "#2952A3";

                Uri postUri = OwnCalendarsUri;
                CalendarEntry createdCalendar = CalendarService.Insert(postUri, calendar);
                absoluteUri = new Uri(createdCalendar.Id.AbsoluteUri);
            }

            String lastFragment = absoluteUri.Segments[absoluteUri.Segments.Length - 1];
            String uriString = String.Format(uriTemplate, lastFragment);
            return new Uri(uriString);            
        }

        public void ListEvents()
        {
            EventQuery query = new EventQuery();
            query.Uri = CalendarUri;
            query.NumberToRetrieve = Int16.MaxValue;

            EventFeed eventFeed = CalendarService.Query(query);
            foreach (EventEntry eventEntry in eventFeed.Entries)
            {
                Console.Write(eventEntry.Title.Text);
                Console.Write(" ( times: ");
                foreach (When when in eventEntry.Times)
                {
                    Console.Write(when.StartTime.ToShortTimeString() + " - " + when.EndTime.ToShortTimeString() + ", ");
                }

                Console.WriteLine(" )");
            }
        }


        public void ClearEvents()
        {
            EventQuery query = new EventQuery();
            query.Uri = CalendarUri;
            query.NumberToRetrieve = Int16.MaxValue;
            
            EventFeed eventFeed = CalendarService.Query(query);            
            AtomFeed batchFeed = new AtomFeed(eventFeed);

            foreach (EventEntry eventEntry in eventFeed.Entries)
            {
                eventEntry.BatchData = new GDataBatchEntryData(GDataBatchOperationType.delete);                
                batchFeed.Entries.Add(eventEntry);
            }

            EventFeed batchResultFeed = (EventFeed)CalendarService.Batch(batchFeed, new Uri(eventFeed.Batch));
            foreach (EventEntry entry in batchResultFeed.Entries)
            {
                if (entry.BatchData.Status.Code != 200 && entry.BatchData.Status.Code != 201)
                {
                    throw new  WebException(entry.BatchData.Status.ToString());
                }
            }
        }

        private Reminder CreateGoogleReminder(SpeakupReminder reminder)
        {
            Reminder greminder = new Reminder();

            switch (reminder.Method)
            {
                case SpeakupBackend.Reminder.ReminderMethod.Email:
                    greminder.Method = Google.GData.Extensions.Reminder.ReminderMethod.email;
                    break;
                case SpeakupBackend.Reminder.ReminderMethod.Sms:
                    greminder.Method = Google.GData.Extensions.Reminder.ReminderMethod.sms;
                    break;
            }

            switch (reminder.Scale)
            {
                case SpeakupBackend.Reminder.ReminderScale.Minutes:
                    greminder.Minutes = reminder.Value;
                    break;
                case SpeakupBackend.Reminder.ReminderScale.Hours:
                    greminder.Hours = reminder.Value;
                    break;
                case SpeakupBackend.Reminder.ReminderScale.Days:
                    greminder.Days = reminder.Value;
                    break;
            }

            return greminder;
        }

        public void AddEvents(List<Class> classes)
        {
            EventQuery query = new EventQuery();
            query.Uri = CalendarUri;
            query.StartTime = DateTime.Now.Date;

            EventFeed eventFeed = CalendarService.Query(query);
            AtomFeed batchFeed = new AtomFeed(eventFeed);
            
            foreach (Class cl in classes)
            {
                String title = cl.Name.Name;
                if (cl.Theme != null && cl.Name.Name != cl.Theme.Name)
                {
                    title += " - " + cl.Theme.Name;
                }

                EventEntry newEvent = new EventEntry(title);
                DateTime start = cl.Time.Date + cl.Time.Begin;
                DateTime end = cl.Time.Date + cl.Time.End;
                newEvent.Times.Add(new When(start, end));
                newEvent.Locations.Add(new Where(null, null, "Speakup School"));

                if (Reminder != null)
                {
                    newEvent.Reminder = CreateGoogleReminder(Reminder);
                }
                
                newEvent.BatchData = new GDataBatchEntryData(GDataBatchOperationType.insert);
                batchFeed.Entries.Add(newEvent);
            }

            EventFeed batchResultFeed = (EventFeed)CalendarService.Batch(batchFeed, new Uri(eventFeed.Batch));
            foreach (EventEntry entry in batchResultFeed.Entries)
            {
                if (entry.BatchData.Status.Code != 200 && entry.BatchData.Status.Code != 201)
                {
                    throw new WebException(entry.BatchData.Status.ToString());
                }
            }
        }
    }
}
